//
//  DDNetTools.swift
//  SinaMicroBlog
//
//  Created by dqw on 15/7/29.
//  Copyright © 2015年 itcast. All rights reserved.
//

import UIKit
import AFNetworking


private let DDErrorDomainName = "DDErrorDomainName"
typealias DDNetFinishedCT = (result:[String:AnyObject]?, error:NSError?) ->()

// MARK: - 定义枚举，错误和方法的枚举
/// 网络访问错误信息 - 枚举，是定义一组类似的值
/// Swift 中枚举可以定义函数和属性，跟`类`有点像
enum DDNetError: Int {
    case emptyDataError = -1
    case emptyTokenError = -2
    case wrongDataFormatError = -3
    
    /// 错误描述
    private var errorDescrption: String {
        switch self {
        case .emptyDataError: return "空数据"
        case .emptyTokenError: return "Token 为空"
        case .wrongDataFormatError: return "数据格式错误"
        }
    }
     // FIXME: 枚举的函数，老师的可以用private，我的怎么就不行。
    func error() -> NSError {
        return NSError(domain: DDErrorDomainName, code: rawValue, userInfo: [DDErrorDomainName: errorDescrption])
    }
}

private enum DDNetMethod: String {
    case POST = "POST"
    case GET = "GET"
}


class DDNetTools: AFHTTPSessionManager {
    
    // 原来的
    // private var clientId = "167165570"
    // private var clientSecret = "efe9033ed60e584f9bd158a1aee4e4b7"
    
    //在微博上面又新建了一个应用。
    // App Key：179170322
    // App Secret：09f21eb15aa4ffaab15524bdaa442bca
    private var clientId = "167165570"
    private var clientSecret = "efe9033ed60e584f9bd158a1aee4e4b7"
    var redirectUri = "http://www.baidu.com"

// MARK: - 网络单例方法，和懒加载形式几乎一样。
    // 网络访问数据的格式添加。
    static let sharedNetTools:DDNetTools = {
        let instance = DDNetTools(baseURL: NSURL(string: "https://api.weibo.com")!)
        instance.responseSerializer.acceptableContentTypes = NSSet(objects: "application/json", "text/json", "text/javascript", "text/plain") as Set<NSObject>
        return instance
        }()
    // MARK: - 登陆的URL，自己拼接的，不能使用BaseURL。
    var oauthUrl: NSURL{
       return NSURL(string:"https://api.weibo.com/oauth2/authorize?client_id=\(clientId)&redirect_uri=\(redirectUri)")!
    }
    
    // MARK: - 对token判断的封装
    private func getAndJudgeAccessToken(finished: DDNetFinishedCT) -> [String: AnyObject]? {
        
        if DDUserAccount.aUserAccount?.access_token == nil {
            finished(result: nil, error: DDNetError.emptyTokenError.error())
            return nil
        }
        return ["access_token": DDUserAccount.aUserAccount!.access_token!]
    }
    
    // MARK: - 得到token的网络方法。
    func getAccessTokenAndSomeUserInfo(code:String, finished : DDNetFinishedCT){
        
        let urlString = "https://api.weibo.com/oauth2/access_token"
        let paras = ["client_id": clientId,
            "client_secret": clientSecret,
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": redirectUri]
        request(DDNetMethod.POST, urlStr: urlString, paras: paras, finished: finished)
    }
    

    // MARK: - 得到另外一些账户信息的网络方法。
    func getAnotherUserInfo(finished:DDNetFinishedCT) {
        
        let urlStr = "2/users/show.json"
        guard var paras = getAndJudgeAccessToken(finished) else {
            return
        }
        paras["uid"] = DDUserAccount.aUserAccount!.uid
        request(DDNetMethod.GET, urlStr: urlStr, paras: paras, finished: finished)
    }
    
    func sendStatus(status: String, image: UIImage?, finished: DDNetFinishedCT) {
        
        let urlStr = "2/statuses/update.json"
        guard var paras = getAndJudgeAccessToken(finished) else {
            return
        }
        paras["status"] = status
        if image == nil {
            request(DDNetMethod.POST, urlStr: urlStr, paras: paras, finished: finished)
        }else {
            uploadCompoundStatus("https://upload.api.weibo.com/2/statuses/upload.json", image: image!, paras: paras, finished: finished)
        }
    }
    private func uploadCompoundStatus(urlStr: String, image: UIImage, paras: [String: AnyObject], finished:DDNetFinishedCT) {
        
        let successCallBack: (NSURLSessionDataTask!, AnyObject!) -> Void = { (_, data) -> Void in
            if let result = data as? [String: AnyObject] {
                finished(result: result, error: nil)
            }else{
                finished(result: nil, error: DDNetError.emptyDataError.error())
            }
        }
        
        let failureCallBack: (NSURLSessionDataTask!, NSError!) -> Void = { (_, error) -> Void in
            
            finished(result: nil, error: error)
        }
        
        let data = UIImagePNGRepresentation(image)
        POST(urlStr, parameters: paras, constructingBodyWithBlock: { ( formData) -> Void in
            formData.appendPartWithFileData(data, name: "pic", fileName:"dqw" , mimeType: "Application/octet-stream")
            }, success: successCallBack, failure: failureCallBack)
    }
    // MARK: - 加载微博j数据
    func loadStatuses(since_id: Int, max_id: Int, finished:DDNetFinishedCT) {
        
        guard var paras = getAndJudgeAccessToken(finished) else {
            
            return
        }
        if since_id > 0 {
            paras["since_id"] = since_id
        }
        if max_id > 0 {
            paras["max_id"] = max_id - 1
        }
        
//        paras["since_id"] = since_id
//        paras["max_id"] = max_id - 1

        let urlStr = "2/statuses/home_timeline.json"
        request(DDNetMethod.GET, urlStr: urlStr, paras: paras, finished: finished)
    }

    // MARK: - 网络访问方法的封装（重点：回调的单独定义，枚举得到方法）闭包：就理解为调用：向外串参数，定义：处理数据。
   private func request(method: DDNetMethod, urlStr: String, paras: [String: AnyObject], finished: DDNetFinishedCT) {
    
        let successCallBack: (NSURLSessionDataTask!, AnyObject!) -> Void = { (_, data) -> Void in
            
            if let result = data as? [String: AnyObject] {
                finished(result: result, error: nil)
            }else{
                finished(result: nil, error: DDNetError.emptyDataError.error())
            }
        }
        
        let failureCallBack: (NSURLSessionDataTask!, NSError!) -> Void = { (_, error) -> Void in
            
            finished(result: nil, error: error)
        }
    
        switch method {
        case .GET: GET(urlStr, parameters: paras, success: successCallBack, failure: failureCallBack)
        case .POST: POST(urlStr, parameters: paras, success: successCallBack, failure: failureCallBack)
        }
    }
    
}
